Tegra: bpmp: suspend/resume handlers
authorVarun Wadekar <[email protected]>
Wed, 4 Apr 2018 18:09:41 +0000 (11:09 -0700)
committerVarun Wadekar <[email protected]>
Thu, 31 Jan 2019 16:49:50 +0000 (08:49 -0800)
This patch adds suspend and resume handlers for the BPMP
interface. Mark the interface as "suspended" before entering
System Suspend and verify that BPMP is alive on exit.

Change-Id: I74ccbc86125079b46d06360fc4c7e8a5acfbdfb2
Signed-off-by: Varun Wadekar <[email protected]>
plat/nvidia/tegra/common/drivers/bpmp/bpmp.c
plat/nvidia/tegra/include/drivers/bpmp.h

index 9a41a9bb5d6638e2bd24b7c329bc6f703802ddc1..31c7d80510418e1d87514d7ee1838e5b3dfb35a4 100644 (file)
@@ -16,7 +16,7 @@
 #include <string.h>
 #include <tegra_def.h>
 
-#define BPMP_TIMEOUT   2
+#define BPMP_TIMEOUT   500 /* 500ms */
 
 static uint32_t channel_base[NR_CHANNELS];
 static uint32_t bpmp_init_state = BPMP_INIT_PENDING;
@@ -115,57 +115,109 @@ int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
 
 int tegra_bpmp_init(void)
 {
-       uint32_t val, base;
+       uint32_t val, base, timeout = BPMP_TIMEOUT;
        unsigned int ch;
        int ret = 0;
 
-       if (bpmp_init_state != BPMP_INIT_COMPLETE) {
+       if (bpmp_init_state == BPMP_INIT_PENDING) {
 
                /* check if the bpmp processor is alive. */
-               val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
-               if (val != SIGN_OF_LIFE) {
-                       return -ENOTSUP;
-               }
+               do {
+                       val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
+                       if (val != SIGN_OF_LIFE) {
+                               mdelay(1);
+                               timeout--;
+                       }
 
-               /* check if clock for the atomics block is enabled */
-               val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V);
-               if ((val & CAR_ENABLE_ATOMICS) == 0) {
-                       ERROR("Clock to the atomics block is disabled\n");
-               }
+               } while ((val != SIGN_OF_LIFE) && (timeout > 0U));
 
-               /* check if the atomics block is out of reset */
-               val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V);
-               if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) {
-                       ERROR("Reset to the atomics block is asserted\n");
-               }
+               if (val == SIGN_OF_LIFE) {
 
-               /* base address to get the result from Atomics */
-               base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET;
+                       /* check if clock for the atomics block is enabled */
+                       val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V);
+                       if ((val & CAR_ENABLE_ATOMICS) == 0) {
+                               ERROR("Clock to the atomics block is disabled\n");
+                       }
 
-               /* channel area is setup by BPMP before signaling handshake */
-               for (ch = 0; ch < NR_CHANNELS; ch++) {
+                       /* check if the atomics block is out of reset */
+                       val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V);
+                       if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) {
+                               ERROR("Reset to the atomics block is asserted\n");
+                       }
 
-                       /* issue command to get the channel base address */
-                       mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) |
-                                     ATOMIC_CMD_GET);
+                       /* base address to get the result from Atomics */
+                       base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET;
 
-                       /* get the base address for the channel */
-                       channel_base[ch] = mmio_read_32(base);
+                       /* channel area is setup by BPMP before signaling handshake */
+                       for (ch = 0; ch < NR_CHANNELS; ch++) {
 
-                       /* increment result register offset */
-                       base += 4U;
-               }
+                               /* issue command to get the channel base address */
+                               mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) |
+                                             ATOMIC_CMD_GET);
 
-               /* mark state as "initialized" */
-               bpmp_init_state = BPMP_INIT_COMPLETE;
+                               /* get the base address for the channel */
+                               channel_base[ch] = mmio_read_32(base);
 
-               /* the channel values have to be visible across all cpus */
-               flush_dcache_range((uint64_t)channel_base, sizeof(channel_base));
-               flush_dcache_range((uint64_t)&bpmp_init_state,
-                                  sizeof(bpmp_init_state));
+                               /* increment result register offset */
+                               base += 4U;
+                       }
+
+                       /* mark state as "initialized" */
+                       bpmp_init_state = BPMP_INIT_COMPLETE;
+
+                       /* the channel values have to be visible across all cpus */
+                       flush_dcache_range((uint64_t)channel_base,
+                                          sizeof(channel_base));
+                       flush_dcache_range((uint64_t)&bpmp_init_state,
+                                          sizeof(bpmp_init_state));
+
+                       INFO("%s: done\n", __func__);
 
-               INFO("%s: done\n", __func__);
+               } else {
+                       ERROR("BPMP not powered on\n");
+                       ret = -ETIMEDOUT;
+               }
        }
 
        return ret;
 }
+
+void tegra_bpmp_suspend(void)
+{
+       /* freeze the interface */
+       bpmp_init_state = BPMP_SUSPEND_ENTRY;
+       flush_dcache_range((uint64_t)&bpmp_init_state, sizeof(bpmp_init_state));
+}
+
+void tegra_bpmp_resume(void)
+{
+       uint32_t val, timeout = 0;
+
+       if (bpmp_init_state == BPMP_SUSPEND_ENTRY) {
+
+               /* check if the bpmp processor is alive. */
+               do {
+
+                       val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
+                       if (val != SIGN_OF_LIFE) {
+                               mdelay(1);
+                               timeout++;
+                       }
+
+               } while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT));
+
+               if (val == SIGN_OF_LIFE) {
+
+                       INFO("%s: BPMP took %d ms to resume\n", __func__, timeout);
+
+                       /* mark state as "initialized" */
+                       bpmp_init_state = BPMP_INIT_COMPLETE;
+
+                       /* state has to be visible across all cpus */
+                       flush_dcache_range((uint64_t)&bpmp_init_state,
+                                          sizeof(bpmp_init_state));
+               } else {
+                       ERROR("BPMP not powered on\n");
+               }
+       }
+}
index 03da6f68b327e232929b07f31a642d1361e4ee68..0046f6cc7617722a6ac423f144e480c67aa0dd55 100644 (file)
@@ -29,6 +29,7 @@
 /* flags to indicate bpmp driver's state */
 #define BPMP_INIT_COMPLETE     0xBEEFF00DU
 #define BPMP_INIT_PENDING      0xDEADBEEFU
+#define BPMP_SUSPEND_ENTRY     0xF00DCAFEU
 
 /* requests serviced by the bpmp */
 #define MRQ_PING               0
@@ -106,6 +107,16 @@ typedef struct mb_data {
  */
 int tegra_bpmp_init(void);
 
+/**
+ * Function to suspend the interface with the bpmp
+ */
+void tegra_bpmp_suspend(void);
+
+/**
+ * Function to resume the interface with the bpmp
+ */
+void tegra_bpmp_resume(void);
+
 /**
  * Handler to send a MRQ_* command to the bpmp
  */